/**
 * This file was created by Nick Popescu for use in SpaceTrader
 */
import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * This is the Controller component class, which ties together the View and the
 * Model, and applies its logic to the game.
 * 
 * @author Nick Popescu
 * @version 1.0
 */

public class Controller {
    
    /**
     * This represents the payer to be used in the Game 
     */
    private Player player;
    
    /**
     * This represents the space the payer travels on for the game 
     */
    private Space space;
    
    /**
     * This represents the game screen used in the UI of the game 
     */
    private GameScreen gameScreen;

    /**
     * A reference to the model component for this presenter
     */
    private final Model myModel;

    /**
     * A reference to the view component for this presenter
     */
    private final View myView;

    /**
     * The maximum skill points allowed for a player
     */
    public static final int MAX_SKILL_POINTS = 16;

    /**
     * 
     * Makes a new Controller that ties together the Model and the View
     * 
     * @param m
     *            the model passed in
     * @param v
     *            the view passed in
     */
    public Controller(Model m, View v) {
	myModel = m;
	myView = v;
	myView.enableAccept(false); // This checks if the buttons should be
				    // pressable
	myView.registerAccept(new ActionListener() {

	    /**
	     * This is used by the Accept button. It detects when the button is
	     * clicked, and then checks if the name is valid. If it is, then the
	     * character creation is handled.
	     * 
	     * @param arg0
	     *            The action event that triggers this method.
	     */
	    @Override
	    public void actionPerformed(ActionEvent arg0) {
		if (isNameValidated(myView.getName(), myView.getDefaultName())) {
		    myView.displayNameError(false);// Hides error message if it
						   // was shown.
		    handleAcceptPress();
		} else {
		    myView.displayNameError(true);
		}
	    }

	});

	myView.detectSkillChange(new ChangeListener() {

	    /**
	     * This is used by the Spinners in the UI. It detects if the
	     * spinners have been changed, and displays how many skill points
	     * are still available for distribution.
	     * 
	     * @param arg0
	     *            The change that triggered the event.
	     */

	    @Override
	    public void stateChanged(ChangeEvent arg0) {
		int sumOfAll = 0;// Sum of currently-selected skills
		for (int i = 0; i < myView.getSpinners().length; i++) {
		    int potentialMax = 0;// The maximum that the current spinner
					 // can be.
		    int sumOfOthers = 0;// Sum of other spinners, not the
					// current one.

		    for (int x = 0; x < myView.getSpinners().length; x++) {
			if (x != i) {
			    sumOfOthers += (Integer) myView.getSpinners()[x]
				    .getValue();// sums other spinners.

			}
		    }
		    potentialMax = MAX_SKILL_POINTS - sumOfOthers;

		    sumOfAll += (Integer) myView.getSpinners()[i].getValue();
		    myView.getSpinners()[i].setModel(new SpinnerNumberModel(
			    (Integer) myView.getSpinners()[i].getValue(),
			    (Integer) 0, (Integer) potentialMax, (Integer) 1));// Sets
									       // the
									       // max
									       // of
									       // the
									       // current
									       // spinner.

		}

		myView.updateSkillsRemaining(MAX_SKILL_POINTS - sumOfAll);// updates
									  // the
									  // UI
									  // to
									  // show
									  // remaining
									  // points.
		checkSkillLevel();// Checks if all the points were spent.

	    }
	});

    }

    /**
     * Handle the Accept button press. Creates a player and gives it a ship.
     */
    private void handleAcceptPress() {

	myModel.createPlayer(myView.getName(), myView.getSkillPointArray());
	Game.setPlayer(player);
	//Game.Player = player;
	myModel.setPlayerShip(new Ship("Gnat"));
	//myModel.getPlayerShip();// Used for this Demo; Prints out the ship's
				// name.

	// MyMode.createSpace()
	space = new Space(player);// This is where the Space grid is created
	//Game.Space = space;
	Game.setSpace(space);
	// myView.showScreen(new SpaceMapScreen(space));

	myView.showScreen(gameScreen = new GameScreen(space, player));// Displays
								      // the
								      // Game
								      // Screen
								      // UI.
	//Game.GameScreen = gameScreen;
	Game.setGameScreen(gameScreen);

    }

    /**
     * Checks if all the skill points were spent. Enables the "Accept" button if
     * they were; otherwise, disables it.
     */
    private void checkSkillLevel() {
	// System.out.println(myView.getSkillPoints());
	if (myView.getSkillPoints() == MAX_SKILL_POINTS) { // Figure out how to
							   // add up points in
							   // the hash table;
	    myView.enableAccept(true);
	} else {
	    myView.enableAccept(false);
	}
    }

    /**
     * Checks if the selected name passes the given criteria. The name has to be
     * between 3 and 13 characters long, and can't be the default value from the
     * text box.
     * 
     * @param name
     *            The entered name that is being checked.
     * @param defaultVal
     *            The default name that is in the text box before it's changed.
     * @return true if the name passes the requirements, false otherwise.
     */
    private boolean isNameValidated(String name, String defaultVal) {
	return name.length() >= 3 && !name.equals(defaultVal) // $codepro.audit.disable numericLiterals
		&& name.length() <= 13; // $codepro.audit.disable numericLiterals
    }

    /**
     * Main startup method for the program. Makes a new controller and starts
     * it. In the process, a new player is created, and a new ConfigScreen is
     * made.
     * 
     * @param args
     *            command line not used
     */
    public static void main(String args[]) {
	final Player player = new Player();
	Game.InitConfigScreen = new InitConfigScreen();
	final Controller theController = new Controller(player,
		Game.InitConfigScreen);
	Game.NewPlayerScreen = Game.InitConfigScreen.getFrame()
		.getContentPane();
	theController.setPlayer(player);// Creates a reference to the Player
					// inside of the Controller.

	// HERE, WE WILL SHOW THE START SCREEN, TO SEE IF WE NEED TO MAKE A NEW
	// PLAYER.
	Game.InitConfigScreen.getFrame().getContentPane().setVisible(false);
	Game.InitConfigScreen.showScreen(new StartScreen());

	theController.start();
    }

    /**
     * start up this controller; Shows the View.
     */
    private void start() {
	myView.show();

    }

    /**
     * @return the string representation of the Controller.
     */
    @Override
    public String toString() {
	return "A controller for configuration screen";
    }

    /**
     * Sets the player, which is used by other methods that need a reference to
     * the player.
     * 
     * @param player
     *            The player of the game that is being controlled.
     */
    public void setPlayer(Player player) {
	this.player = player;
    }

    /**
     * Sets the space, which is used by other methods that need a reference to
     * the space.
     * 
     * @param space
     *            The space map with the planets.
     */
    public void setSpace(Space space) {
	this.space = space;
    }

}